<?php
declare (strict_types=1);

namespace app\admin\controller\acl;

use app\admin\controller\CommonController;
use app\common\model\AclRole;
use app\common\model\AclUser;
use ffhome\common\util\CommonUtil;
use ffhome\frame\model\AclUserRole;
use think\facade\Cache;
use think\facade\Db;

abstract class User extends CommonController
{
    protected $modelName = AclUser::MODEL_NAME;
    protected $alias = 'u';
    protected $deleteField = 'delete_time';

    abstract protected function getType(): int;

    protected function getSearchFields(): string
    {
        $roleEnable = AclRole::ENABLE;
        $ACL_ROLE = AclRole::MODEL_NAME;
        $ACL_USER_ROLE = AclUserRole::MODEL_NAME;
        return "{$this->alias}.id,{$this->alias}.username,{$this->alias}.nickname,{$this->alias}.avatar,{$this->alias}.mobile,{$this->alias}.login_num,{$this->alias}.status,{$this->alias}.update_time"
            . ",(select group_concat(r.name) from {$this->prefix}{$ACL_ROLE} r, {$this->prefix}{$ACL_USER_ROLE} ur where r.id=ur.role_id and ur.user_id={$this->alias}.id and r.status={$roleEnable} order by r.sort) role";
    }

    protected function getSearchDefaultSort(): array
    {
        return ["{$this->alias}.update_time" => 'desc'];
    }

    protected function buildWhere(array $param): array
    {
        $where = parent::buildWhere($param);
        $where[] = ["{$this->alias}.type", '=', $this->getType()];
        //分类搜索处理
        $roleId = request()->get('role_id', 0, 'intval');
        if (!empty($roleId)) {
            $ACL_USER_ROLE = AclUserRole::MODEL_NAME;
            $where[] = ["{$this->alias}.id", 'exp', Db::raw("in (select ur.user_id from {$this->prefix}{$ACL_USER_ROLE} ur where ur.role_id={$roleId})")];
        }

        return $where;
    }

    protected function getExportHeader()
    {
        return [
            [lang('common.id'), 'id']
            , [lang('user.username'), 'username']
            , [lang('user.nickname'), 'nickname']
            , [lang('user.mobile'), 'mobile']
            , [lang('user.login_num'), 'login_num']
            , [lang('common.update_time'), 'update_time']
        ];
    }

    protected function setDefaultValueInAddPage(array $row): array
    {
        $row['role_ids'] = [];
        $row['avatar'] = sysValue('default_avatar');
        return parent::setDefaultValueInAddPage($row);
    }

    protected function getFilterFields(): array
    {
        return ['id', 'avatar', 'username', 'nickname', 'mobile', 'status'];
    }

    protected function validateRule(array $data): array
    {
        return ['avatar|' . lang('user.avatar') => 'require'
            , 'username|' . lang('user.username') => 'require'
            , 'nickname|' . lang('user.nickname') => 'require'
            , 'mobile|' . lang('user.mobile') => 'require'
            , 'status|' . lang('common.status') => 'require'
        ];
    }

    protected function onBeforeAdd(array &$data)
    {
        parent::onBeforeAdd($data);
        if ($this->usernameExist($data['username']) != 0) {
            $this->error(lang('user.username_exist'));
        }

        $data['type'] = $this->getType();
        $data['password'] = CommonUtil::password(sysValue('default_password'));
    }

    protected function onAfterAdd(array &$data)
    {
        $this->saveRole($data['id']);
        parent::onAfterAdd($data);
    }

    protected function editPage(array $row)
    {
        $row['role_ids'] = Db::name(AclUserRole::MODEL_NAME)->alias('ur')
            ->leftJoin(AclRole::MODEL_NAME . ' r', 'r.id=ur.role_id')
            ->where(['ur.user_id' => $row['id'], 'r.status' => AclRole::ENABLE])
            ->column('ur.role_id');
        return parent::editPage($row);
    }

    protected function onAfterEdit(array &$data, array $row)
    {
        $this->saveRole($data['id']);
        parent::onAfterEdit($data, $row);
    }

    private function saveRole($id)
    {
        Db::name(AclUserRole::MODEL_NAME)->where('user_id', $id)->delete();
        $roleIds = array_keys($this->request->post('role_ids', []));
        $data = array_map(function ($roleId) use ($id) {
            return ['role_id' => $roleId, 'user_id' => $id];
        }, $roleIds);
        Db::name(AclUserRole::MODEL_NAME)->insertAll($data);
    }

    public function checkUsername()
    {
        $count = $this->usernameExist($this->request->param('username'), $this->request->param('id'));
        if ($count == 0) {
            $this->success();
        }
        $this->error(lang('user.username_exist'));
    }

    private function usernameExist(string $username, $id = '')
    {
        $where = [['username', '=', $username]];
        if (!empty($id)) {
            $where[] = ['id', '<>', $id];
        }
        return Db::name($this->modelName)->where($where)->count();
    }

    protected function clearCache()
    {
        parent::clearCache();
        //清空权限相关缓存
        Cache::tag('authority')->clear();
    }

    public function password(int $id)
    {
        $row = $this->getModelInfo($id);
        if (!$this->request->isAjax()) {
            $this->assign('row', $row);
            return $this->fetch();
        }
        $param = $this->request->param();
        $rule = [
            'password|' . lang('user.password') => 'require',
            'password_again|' . lang('user.password_again') => 'require',
        ];
        $this->validate($param, $rule);
        if ($param['password'] != $param['password_again']) {
            $this->error(lang('user.password_not_equal'));
        }
        Db::name($this->modelName)->update(['id' => $id, 'password' => CommonUtil::password($param['password'])]);
        $this->success(lang('common.save_success'));
    }
}
